#include "cmdProcess.h"
#include <stdio.h>
#include "main.h"

typedef struct{
    const char *cmdName;
    const char *brief;
    void (*pCmdCallback)(uint8_t argc, char *argv[]);
}cmdItem;

void cmd_cb_echo(uint8_t argc, char *argv[]);
void cmd_cb_help(uint8_t argc, char *argv[]);
void cmd_cb_hello(uint8_t argc, char *argv[]);
void cmd_cb_adc_read(uint8_t argc, char *argv[]);

cmdItem cmdList[] = {
    {
        .cmdName = "echo",
        .brief = "return params to test uart",
        .pCmdCallback = cmd_cb_echo,
    },
    {
        .cmdName = "hello",
        .brief = "hello",
        .pCmdCallback = cmd_cb_hello,
    },
    {
        .cmdName = "help",
        .brief = "print brief of commands",
        .pCmdCallback = cmd_cb_help,
    },

    {
        .cmdName = "adc_read",
        .brief = "read adc value",
        .pCmdCallback = cmd_cb_adc_read,
    },


    // end of list:
    {
        .cmdName = " ",
        .pCmdCallback = NULL,
    },
};

int my_str_cmp(const char *str1, char *str2){
    uint32_t i;
    for(i = 0; i < CMD_MAX_ARG_COUNTS; i++){
        if(str1[i] == '\0' || str1[i] == ' '){
            if(str2[i] == '\0' || str2[i] == ' ' || str2[i] == '\n'){
                str2[i] = '\0';
                return 0;
            }else {
                return -1;
            }
        }
        if(str1[i] != str2[i]){
            return -1;
        }
    }

    return 0;
}

void cmd_cb_echo(uint8_t argc, char *argv[]){
    if(argc > 1){
        if(my_str_cmp("-h", argv[1]) == 0){
            goto Useage_echo;
        }
        LOG_FMT(PRINT_LOG"%s\n", argv[1]);
    }else {
        LOG_FMT(PRINT_WARNNING"Need param to echo!\n");
    }
    return ;
Useage_echo:
    LOG_FMT(PRINT_LOG"Useage: This function will return the first param to test uart\n");
}

void cmd_cb_hello(uint8_t argc, char *argv[]){
    LOG_FMT(PRINT_LOG"Ciallo World~ (∠・ω< )⌒☆\n");
}

void cmd_cb_help(uint8_t argc, char *argv[]){
    uint8_t i;
    
    if(argc > 1){
        for(i = 0; cmdList[i].cmdName[0] != ' '; i ++){
            if(my_str_cmp(cmdList[i].cmdName, argv[1]) == 0){
                LOG_FMT(PRINT_LOG"%s   -   %s\n", cmdList[i].cmdName, cmdList[i].brief);
                return;
            }
        }
    }else {
        for(i = 0; cmdList[i].cmdName[0] != ' '; i ++){
            LOG_FMT(PRINT_LOG"%s:\n\t%s\n", cmdList[i].cmdName, cmdList[i].brief);
        }

        return ;
    }

    LOG_FMT(PRINT_WARNNING"Unknown cmd: %s, Type /help to list all commands\n", argv[1]);
}

uint16_t const *pVrefbuf15 = (uint16_t const *)0x1FFF002E; // 内部 1.5V 参考电压出厂校准值地址
void cmd_cb_adc_read(uint8_t argc, char *argv[]){
    if(argc != 2){
        goto Useage_adc_read;
    }
    
    if(argv[1][0] != '-' || argv[1][1] != 'r'){
        goto Useage_adc_read;
    }

    switch(argv[1][2]){
        case '0':
            LOG_FMT(PRINT_LOG"ADC red stone BACK channel value: %d\n", adc_redstone_back);
            LOG_FMT(PRINT_LOG"RS conversion: %dmV\n", (uint16_t)(adc_redstone_back*real_Vref*ADC_RS_K));
            break;
        case '1':
            LOG_FMT(PRINT_LOG"ADC red stone LEFT channel value: %d\n", adc_redstone_left);
            LOG_FMT(PRINT_LOG"RS conversion: %dmV\n", (uint16_t)(adc_redstone_left*real_Vref*ADC_RS_K));
            break;
        case '2':
            LOG_FMT(PRINT_LOG"ADC red stone RIGHT channel value: %d\n", adc_redstone_right);
            LOG_FMT(PRINT_LOG"RS conversion: %dmV\n", (uint16_t)(adc_redstone_right*real_Vref*ADC_RS_K));
            break;
        case '3':
            LOG_FMT(PRINT_LOG"ADC temp channel value: %d\n", adc_temp);
            LOG_FMT(PRINT_LOG"ADC temp conversion: %.1f\n", (adc_temp*real_Vref/4095 - 760)/2.5 + 30);
            // LOG_FMT(PRINT_LOG"ADC temp conversion: %.1f\n", (adc_temp*0.3663- 760)/2.5 + 30);
            break;
        case '4':
            LOG_FMT(PRINT_LOG"ADC Vref channel value: %d\n", adc_vref);
            LOG_FMT(PRINT_LOG"ADC Vref conversion: %dmV\n", real_Vref);
            break;
        case '5':
            LOG_FMT(PRINT_LOG"ADC Vref inside value: 0x%x\n", *pVrefbuf15);
            break;
        default:
            LOG_FMT(PRINT_WARNNING"Unconfigured channel: %c\n", argv[1][3]);
            break;
    }

    return ;

Useage_adc_read:
    LOG_FMT(PRINT_LOG"Useage: This function will read adc value of some channel\n");
    LOG_FMT(PRINT_LOG"Example: /adc_read -r2\n");
}


void process_command(char *cmd){
    uint32_t i = 0;
    uint8_t index = 1;
    char *argv[CMD_MAX_ARG_COUNTS] = {
        [0] = cmd + 1,
    };

    if(!(cmd[0] == '/' || cmd[0] == '#')){ // 非指令
        LOG_FMT(PRINT_WARNNING"Unknow format!\n");
        // LOG_FMT(PRINT_DEBUG"%s\n", cmd);
        return;
    }

    for(i = 1; (cmd[i] != '\0') && (i < CMDBUF_SIZE - 1) && (index < CMD_MAX_ARG_COUNTS - 1); i ++){
        if((cmd[i-1] == ' ') && (cmd[i] != ' ')){
            argv[index] = &cmd[i];
            index ++;
            cmd[i-1] = '\0';
        }
    }

    for(i = 0; cmdList[i].cmdName[0] != ' '; i ++){
        if(my_str_cmp(cmdList[i].cmdName, argv[0]) == 0){
            if(cmdList[i].pCmdCallback != NULL){
                argv[0] = cmd;
                cmdList[i].pCmdCallback(index, argv);
            }else {
                LOG_FMT(PRINT_ERROR"Callback function of \"%s\" is not define!\n", argv[0]);
            }
            return;
        }
    }

    LOG_FMT(PRINT_WARNNING"Unknown cmd: %s\n", argv[0]);
    LOG_FMT(PRINT_LOG"Type /help to list all commands\n");
}
